iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 18
1

定義目標

有位友人想要點餐,他問能否可以有個 command line 的方式來上傳 ibon 檔案,雖然我不知道他會怎麼使用它,但其實能幫人家省時間就是一件有價值的事情,那我們今天的主題就來挑戰用 ibon 自動上傳檔案吧。


實際探訪

iBon 上傳的網址是 https://www.ibon.com.tw/mobile/printscan/D0111_fileupload_innerifrm.aspx ,點進去以後,能看到要填入的欄位不會很多,主要是姓名、Email、上傳文件和一個 checkbox。輸入完畢後按「確認上傳」,這邊可以看到接下來會送出一個 Content-Type:multipart/form-data; 的 post request,裡面的 post form data 有 __VIEWSTATE__EVENTVALIDATIONhsTimetxtUserNametxtEmailfuFilechkboxAgreelnkbtnUpload

裡面大概最有技術難度的是 __VIEWSTATE__EVENTVALIDATION,之前的「台彩的銷售地點」有提到,這是 asp.net 的一種狀態的驗證機制,所以我們必須模擬出這兩個數值出來,才能正確地送出。

接下來我們觀察到,post request 的 response 並沒有內容,而整個流程再送出之後,主動的再發出一個 get request,而我們所需要的取件編號,就在這個 request 裡面。


分解研究

我們若要上傳檔案,那麼會拆解成以下兩個步驟:

  1. 送出 post request 上傳資訊
  2. 送出 get request 取得取件編號

那我們就先來模擬一下我們所送出的 post request,將 url、method、header、form data 輸入進 postman,送出後是有回傳 200。

接下來我們在模擬發一個 get request 來取得取件編號,這邊有成功取得,整個過程應該就沒問題了。


實作程式碼

取得驗證參數

之前我們的做法是直接使用已經得到的 __VIEWSTATE__EVENTVALIDATION,這次我們不要使用已經找出來的,我們使用網頁來模擬產出,所以在先模擬人工走到上傳頁面,取得 __VIEWSTATE__EVENTVALIDATION

request('https://www.ibon.com.tw/mobile/printscan/D0111_fileupload_innerifrm.aspx', (err, res, body)=>{
  var $ = cheerio.load(body)
  var __VIEWSTATE = $('#__VIEWSTATE').val()
  var __EVENTVALIDATION = $('#__EVENTVALIDATION').val()
})

post request

接下來我們就來實作 post request

request('https://www.ibon.com.tw/mobile/printscan/D0111_fileupload_innerifrm.aspx', (err, res, body)=>{
  var $ = cheerio.load(body)
  var __VIEWSTATE = $('#__VIEWSTATE').val()
  var __EVENTVALIDATION = $('#__EVENTVALIDATION').val()

  var options = {
    url: 'https://www.ibon.com.tw/mobile/printscan/D0111_fileupload_innerifrm.aspx',
    method: 'post',
    headers: {
      'Content-Type': 'multipart/form-data',
    },
    formData: {
      'fuFile': fs.createReadStream(__dirname + '/test.pdf'),
      '__VIEWSTATE': __VIEWSTATE,
      '__EVENTVALIDATION': __EVENTVALIDATION,
      'txtUserName': 'Howard',
      'chkboxAgree': 'on',
      'lnkbtnUpload': '確認上傳',
      'txtEmail': 'tnstiger@gmail.com',
    }
  }
  
  request(options, (err, res, body)=>{
    
  })
})

取得取件編號

最後我們再發個 get request 來取得編號就可以了。

request('https://www.ibon.com.tw/mobile/printscan/D0111_fileupload_info.aspx', (err, res, body)=>{
  var $ = cheerio.load(body)
  console.log($('td span.valignmiddle').text().trim());
})

完整程式碼

const request = require('request').defaults({jar: true});
const cheerio = require('cheerio');
const fs = require('fs');

request('https://www.ibon.com.tw/mobile/printscan/D0111_fileupload_innerifrm.aspx', (err, res, body)=>{
  var $ = cheerio.load(body)
  var __VIEWSTATE = $('#__VIEWSTATE').val()
  var __EVENTVALIDATION = $('#__EVENTVALIDATION').val()

  var options = {
    url: 'https://www.ibon.com.tw/mobile/printscan/D0111_fileupload_innerifrm.aspx',
    method: 'post',
    headers: {
      'Content-Type': 'multipart/form-data',
    },
    formData: {
      'fuFile': fs.createReadStream(__dirname + '/test.pdf'),
      '__VIEWSTATE': __VIEWSTATE,
      '__EVENTVALIDATION': __EVENTVALIDATION,
      'txtUserName': 'Howard',
      'chkboxAgree': 'on',
      'lnkbtnUpload': '確認上傳',
      'txtEmail': 'tnstiger@gmail.com',
    }
  }
  request(options, (err, res, body)=>{
    request('https://www.ibon.com.tw/mobile/printscan/D0111_fileupload_info.aspx', (err, res, body)=>{
      var $ = cheerio.load(body)
      console.log($('td span.valignmiddle').text().trim());
    })
  })
})


衍伸應用

基本上在網頁上的任何行為都是有機會被自動化的,尤其是遇到批量的時候,更能幫我們省下很多寶貴的時間。

這次的主題,其實可以再加上個自動產出報表和 cron 排成上傳,這樣就能夠讓公司業務可以隨時地在 7-11 列印出今天的行程或報表。爬蟲和自動化並不是單一動作,組合技會更有價值。


上一篇
漫畫抓取
下一篇
電影場次快速查詢
系列文
爬蟲始終來自於墮性34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
pjchender
iT邦新手 3 級 ‧ 2018-01-05 15:14:20

ibon 上可能一下多了很多檔案,哈哈

我要留言

立即登入留言